"""
工作流管理器
协调剪映草稿的下载和导出完整流程
"""

import os
import time
import logging
import threading
from datetime import datetime
from typing import Dict, Any, Optional, Callable
from dataclasses import dataclass, field
from enum import Enum

try:
    # 尝试相对导入（当作为模块使用时）
    from .jianying_helper_controller import JianyingHelperController
    from .export_controller import ExportController, ExportResolution, ExportFramerate
except ImportError:
    # 直接导入（当直接运行时）
    from jianying_helper_controller import JianyingHelperController
    from export_controller import ExportController, ExportResolution, ExportFramerate


class WorkflowStatus(Enum):
    """工作流状态枚举"""
    PENDING = "pending"          # 等待开始
    DOWNLOADING = "downloading"  # 下载中
    WAITING = "waiting"         # 等待草稿出现
    EXPORTING = "exporting"     # 导出中
    COMPLETED = "completed"     # 完成
    FAILED = "failed"           # 失败


@dataclass
class WorkflowTask:
    """工作流任务"""
    task_id: str
    url: str
    output_path: Optional[str] = None
    draft_name: Optional[str] = None
    resolution: Optional[ExportResolution] = None
    framerate: Optional[ExportFramerate] = None
    status: WorkflowStatus = WorkflowStatus.PENDING
    message: str = ""
    progress: float = 0.0
    created_at: datetime = field(default_factory=datetime.now)
    started_at: Optional[datetime] = None
    completed_at: Optional[datetime] = None
    result: Optional[Dict[str, Any]] = None


class WorkflowManager:
    """工作流管理器"""

    def __init__(self):
        self._helper_controller = None  # 懒加载
        self.export_controller = ExportController()
        self.tasks: Dict[str, WorkflowTask] = {}
        self.running_tasks: Dict[str, threading.Thread] = {}

        # 配置日志
        self.logger = logging.getLogger(__name__)
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
            self.logger.setLevel(logging.INFO)

    @property
    def helper_controller(self):
        """懒加载JianyingHelperController，只在需要时创建"""
        if self._helper_controller is None:
            self._helper_controller = JianyingHelperController()
        return self._helper_controller

    def create_task(self,
                   task_id: str,
                   url: str,
                   output_path: Optional[str] = None,
                   draft_name: Optional[str] = None,
                   resolution: Optional[ExportResolution] = None,
                   framerate: Optional[ExportFramerate] = None) -> WorkflowTask:
        """创建新的工作流任务"""

        if task_id in self.tasks:
            raise ValueError(f"任务ID {task_id} 已存在")

        task = WorkflowTask(
            task_id=task_id,
            url=url,
            output_path=output_path,
            draft_name=draft_name,
            resolution=resolution,
            framerate=framerate
        )

        self.tasks[task_id] = task
        self.logger.info(f"创建新任务: {task_id}")
        return task

    def start_task(self, task_id: str) -> bool:
        """启动工作流任务"""
        if task_id not in self.tasks:
            self.logger.error(f"任务 {task_id} 不存在")
            return False

        task = self.tasks[task_id]

        if task.status != WorkflowStatus.PENDING:
            self.logger.error(f"任务 {task_id} 状态不是pending，无法启动")
            return False

        if task_id in self.running_tasks:
            self.logger.error(f"任务 {task_id} 已在运行中")
            return False

        # 在新线程中执行任务
        thread = threading.Thread(target=self._execute_task, args=(task_id,))
        thread.daemon = True
        self.running_tasks[task_id] = thread
        thread.start()

        self.logger.info(f"启动任务: {task_id}")
        return True

    def _execute_task(self, task_id: str):
        """执行工作流任务"""
        task = self.tasks[task_id]

        try:
            task.started_at = datetime.now()
            self.logger.info(f"开始执行任务: {task_id}")

            # 步骤1: 下载草稿
            self._update_task_status(task_id, WorkflowStatus.DOWNLOADING, "开始下载草稿", 10.0)
            download_result = self._download_draft(task)

            if not download_result["success"]:
                self._update_task_status(task_id, WorkflowStatus.FAILED,
                                       f"下载失败: {download_result['message']}", 0.0)
                task.result = download_result
                return

            # 步骤2: 等待草稿出现在剪映中
            self._update_task_status(task_id, WorkflowStatus.WAITING, "等待草稿出现在剪映中", 30.0)
            draft_name = self._wait_for_draft(task)

            if not draft_name:
                self._update_task_status(task_id, WorkflowStatus.FAILED, "草稿未能及时出现在剪映中", 0.0)
                return

            task.draft_name = draft_name

            # 步骤3: 导出草稿
            self._update_task_status(task_id, WorkflowStatus.EXPORTING, "开始导出草稿", 50.0)
            export_result = self._export_draft(task)

            if not export_result["success"]:
                self._update_task_status(task_id, WorkflowStatus.FAILED,
                                       f"导出失败: {export_result['message']}", 0.0)
                task.result = export_result
                return

            # 完成
            self._update_task_status(task_id, WorkflowStatus.COMPLETED, "任务完成", 100.0)
            task.result = export_result
            task.completed_at = datetime.now()

            self.logger.info(f"任务 {task_id} 执行完成")

        except Exception as e:
            self.logger.error(f"任务 {task_id} 执行异常: {e}")
            import traceback
            self.logger.error(f"异常详情: {traceback.format_exc()}")
            self._update_task_status(task_id, WorkflowStatus.FAILED, f"执行异常: {str(e)}", 0.0)
        finally:
            # 清理运行中的任务记录
            if task_id in self.running_tasks:
                del self.running_tasks[task_id]

    def _download_draft(self, task: WorkflowTask) -> Dict[str, Any]:
        """下载草稿"""
        self.logger.info(f"开始下载草稿: {task.url}")
        return self.helper_controller.download_draft(task.url, timeout=120.0)

    def _wait_for_draft(self, task: WorkflowTask, max_wait_time: float = 60.0) -> Optional[str]:
        """等待草稿出现在剪映中"""
        self.logger.info("等待草稿出现在剪映中...")

        start_time = time.time()
        check_interval = 5.0  # 每5秒检查一次

        # 如果已经指定了草稿名称，直接检查该名称
        if task.draft_name:
            while time.time() - start_time < max_wait_time:
                if self.export_controller.find_draft(task.draft_name):
                    self.logger.info(f"找到草稿: {task.draft_name}")
                    return task.draft_name
                time.sleep(check_interval)
        else:
            # 如果没有指定草稿名称，这里可以实现更智能的草稿检测逻辑
            # 比如获取草稿列表，找到最新的草稿等
            self.logger.warning("未指定草稿名称，无法自动检测草稿")
            # 暂时等待一段时间，假设草稿已经下载完成
            time.sleep(10)
            return "未知草稿"  # 返回一个默认名称

        self.logger.warning(f"等待{max_wait_time}秒后仍未找到草稿")
        return None

    def _export_draft(self, task: WorkflowTask) -> Dict[str, Any]:
        """导出草稿"""
        if not task.draft_name:
            return {
                "success": False,
                "message": "草稿名称未指定"
            }

        self.logger.info(f"开始导出草稿: {task.draft_name}")
        return self.export_controller.export_draft(
            draft_name=task.draft_name,
            output_path=task.output_path,
            resolution=task.resolution,
            framerate=task.framerate,
            timeout=1800  # 30分钟超时
        )

    def _update_task_status(self, task_id: str, status: WorkflowStatus,
                          message: str, progress: float):
        """更新任务状态"""
        if task_id in self.tasks:
            task = self.tasks[task_id]
            task.status = status
            task.message = message
            task.progress = progress
            self.logger.info(f"任务 {task_id}: {status.value} - {message} ({progress:.1f}%)")

    def get_task_status(self, task_id: str) -> Optional[Dict[str, Any]]:
        """获取任务状态"""
        if task_id not in self.tasks:
            return None

        task = self.tasks[task_id]
        return {
            "task_id": task.task_id,
            "status": task.status.value,
            "message": task.message,
            "progress": task.progress,
            "url": task.url,
            "draft_name": task.draft_name,
            "output_path": task.output_path,
            "created_at": task.created_at.isoformat(),
            "started_at": task.started_at.isoformat() if task.started_at else None,
            "completed_at": task.completed_at.isoformat() if task.completed_at else None,
            "result": task.result
        }

    def list_tasks(self) -> Dict[str, Any]:
        """获取所有任务列表"""
        tasks_list = []
        for task_id, task in self.tasks.items():
            tasks_list.append({
                "task_id": task.task_id,
                "status": task.status.value,
                "message": task.message,
                "progress": task.progress,
                "url": task.url,
                "draft_name": task.draft_name,
                # 统一字段名: created_time, start_time, end_time (与com_thread_manager保持一致)
                "created_time": task.created_at.isoformat(),
                "start_time": task.started_at.isoformat() if task.started_at else None,
                "end_time": task.completed_at.isoformat() if task.completed_at else None,
                # 保留旧字段名以兼容
                "created_at": task.created_at.isoformat(),
                "started_at": task.started_at.isoformat() if task.started_at else None,
                "completed_at": task.completed_at.isoformat() if task.completed_at else None
            })

        return {
            "tasks": tasks_list,
            "running_count": len(self.running_tasks),
            "total_count": len(self.tasks),
            "timestamp": datetime.now().isoformat()
        }

    def cancel_task(self, task_id: str) -> bool:
        """取消任务"""
        if task_id not in self.tasks:
            return False

        task = self.tasks[task_id]

        # 如果任务正在运行，标记为失败
        if task_id in self.running_tasks:
            self._update_task_status(task_id, WorkflowStatus.FAILED, "任务被取消", 0.0)
            # 注意：Python的线程无法强制终止，这里只是标记状态
            # 实际的线程可能仍在运行，但会在检查状态时退出

        return True

    def cleanup_completed_tasks(self, older_than_hours: int = 24):
        """清理已完成的任务"""
        current_time = datetime.now()
        tasks_to_remove = []

        for task_id, task in self.tasks.items():
            if task.status in [WorkflowStatus.COMPLETED, WorkflowStatus.FAILED]:
                if task.completed_at and (current_time - task.completed_at).total_seconds() > older_than_hours * 3600:
                    tasks_to_remove.append(task_id)

        for task_id in tasks_to_remove:
            del self.tasks[task_id]
            self.logger.info(f"清理任务: {task_id}")

        return len(tasks_to_remove)

    def execute_workflow(self,
                        url: str,
                        output_path: Optional[str] = None,
                        draft_name: Optional[str] = None,
                        resolution: Optional[ExportResolution] = None,
                        framerate: Optional[ExportFramerate] = None,
                        task_id: Optional[str] = None) -> Dict[str, Any]:
        """执行完整的工作流程（同步版本，用于简单调用）"""

        if not task_id:
            task_id = f"task_{int(time.time())}"

        try:
            # 创建任务
            task = self.create_task(
                task_id=task_id,
                url=url,
                output_path=output_path,
                draft_name=draft_name,
                resolution=resolution,
                framerate=framerate
            )

            # 直接在当前线程执行（同步）
            self._execute_task(task_id)

            # 返回最终结果
            return self.get_task_status(task_id)

        except Exception as e:
            self.logger.error(f"执行工作流异常: {e}")
            return {
                "success": False,
                "message": f"工作流执行异常: {str(e)}",
                "task_id": task_id,
                "timestamp": datetime.now().isoformat()
            }